/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
/**
 *
 * $Id: BehaviourClient.hpp,v 1.6 2009-05-13 07:18:16 amaula Exp $
 *
 * \file
 * \brief MaCI - Behaviour Interface Client header
 * \author Matthieu Myrsky <matthieu.myrsky@tkk.fi>
 *
 */
#ifndef _MACI_INTERFACE_BEHAVIOURCLIENT_HPP_
#define _MACI_INTERFACE_BEHAVIOURCLIENT_HPP_

#include "MaCI.hpp"
#include "BehaviourData.hpp"
#include "thread.hpp"
#include "sync.hpp"
#include <map>

// Forward declare gimi::GIMI
namespace gimi {
  class GIMI;
}

namespace MaCI {
  namespace Behaviour {

 // Forward declarations
    class CBehaviourData;
    class CBehaviourClient;

    /** Behaviour event types.
     */
    enum EBehaviourNotifyers {
      KNotifyEventBehaviourControl = 0,///< Behaviour control element received and stored
      KNotifyInfoReply             = 1
    };
    class CBehaviourClientCallback
    {
    public:

      CBehaviourClientCallback() {}
      virtual ~CBehaviourClientCallback() {}


      /** Handler function for BehaviourData event.
       *
       * This function is called when the BehaviourClient receives new
       * data from the server.
       *
       * \note <b>Keep this function simple & fast as it will block the 
       * data receiving thread while executing!</b>
       *
       * @param[in] aData       Constant reference to CBehaviourData element 
       *                        containing the received event.
       * @param[in] aDataSequence Sequence number of the received data. 
       *                        This should increment by one on each call.
       * @param[in] aBehaviourClient Reference to BehaviourClient 
       *                        instance which received this event.
       */
      virtual void OnBehaviourCtrlEvent(const CBehaviourData &aData, 
                                        const unsigned int aDataSequence,
                                        CBehaviourClient &aBehaviourClient) = 0;

      /** Handler function for BehaviourData event.
       *
       * This function is called when the BehaviourClient receives new
       * data from the server.
       *
       * \note <b>Keep this function simple & fast as it will block the 
       * data receiving thread while executing!</b>
       *
       * @param[in] aData       Constant reference to CBehaviourData element 
       *                        containing the received event.
       * @param[in] aDataSequence Sequence number of the received data. 
       *                        This should increment by one on each call.
       * @param[in] aBehaviourClient Reference to BehaviourClient 
       *                        instance which received this event.
       */
      virtual void OnBehaviourStateEvent(const CBehaviourData &aData, 
                                         const unsigned int aDataSequence,
                                         CBehaviourClient &aBehaviourClient) = 0;
    };
    
    /** MaCI - Behaviour Client interface.
     * 
     * This class contains the methods and types for using
     * a MaCI::Behaviour service in the GIMnet.
     */
    class CBehaviourClient : private gim::CSync,
                            private gim::CThread,
                            public MaCI::CMaCI
    {
    public:
      /** Constructor.
       * 
       * Constructor of the BehaviourClient. This requires;
       * a pointer to Initialized and connected GIMI, minor
       * number of this interface (Used as GIMI minor number)
       *
       * @param[in] aGIMIPtr Pointer to GIMI used for communication
       * @param[in] aInterfaceMinor Interface minor number. Usually
       *            used to indicate the instance of devices of same
       *            type.
       */     
      CBehaviourClient(gimi::GIMI *aGIMIPtr, const int aInterfaceMinor = -1);

      
      /** Destructor.
       */
      ~CBehaviourClient();

      /**
       * Starts behaviour
       *
       * @return  True if message sent
       */
      bool SetStart();

      /**
       * Stops the behaviour
       *
       * @return  True if message sent
       */
      bool SetStop();

      /**
       * Gets behaviour control event.
       *
       * @param[out] aData      PositionData is copied here on succesfull call.
       * @param aSequence       Pointer to sequence number. If this is NULL,
       *                        the most recent position is returned immediately.
       *                        If this is not NULL, the value pointed
       *                        should be set to -1 on the first call to this function.
       *                        After each call, the sequence number of the returned
       *                        data is stored here. If user wants to read all the
       *                        measures available, this value should not be
       *                        modified after the first call.
       * @param[in] aTimeout_ms Timeout value. If the operation is not completed
       *                        before timeout is reached, the operation fails.
       * @return                true - Operation was succesfull, new data is copied
       *                        to provided location.
       *                        false - Operation failed; timeout or generic error
       *                        encountered.
       */
      bool GetBehaviourControlEvent(CBehaviourData &aData,
                                    int *aSequence,
                                    const int aTimeout_ms);

      /**
       * Gets behaviour information
       *
       * @param[out] aInfo      TBehaviourInformation is copied here on succesfull call.
       *
       * @param[in] aTimeout_ms Timeout value. If the operation is not completed
       *                        before timeout is reached, the operation fails.
       * @return                true - Operation was succesfull, new data is copied
       *                        to provided location.
       *                        false - Operation failed; timeout or generic error
       *                        encountered.
       */
      bool GetBehaviourInfo(TBehaviourInformation &aInfo,
                            const int aTimeout_ms);


      /** Assigns the Behaviour client callback function. 
       *
       * This sets a function object for calling a behaviour client
       * callback. If this is set, the interface calls the assigned
       * functions immediately when event is available.
       * 
       * \note As the function is run in the context of the receiving
       * thread, user must make sure that the callback function is
       * fast. As if the function executes too long, receiving events
       * is interrupted.
       *
       * @param[in] aBehaviourClientCallback Pointer to class implementing the interface
       *                                  CBehaviourClientCallback.
       */
      void SetBehaviourClientCallback(CBehaviourClientCallback *aBehaviourClientCallback) {
        iBehaviourClientCallback = aBehaviourClientCallback;
      }

      /** Get Behaviour State
       * Returns if the behaviour is running or not
       *
       * @return                          state of the behaviour. True for running, false if not
       */
      bool GetBehaviourState(void);

    protected:
      /** Open client interface.
       */
      EMaCIError DoOpen(void);


      /** Close client interface.
       */
      EMaCIError DoClose(void);


    private:
      /// Thread runner function. Is in charge of receiving events.
      int ThreadFunction(const int aThreadNumber);
      int ProcessMessage(const gimi::GIMIMessage &msg);
      bool iBehaviourState;
      /// Last PositionData is stored here.
      CBehaviourData iBehaviourData;

      TBehaviourInformation iBehaviourInfo;
      int iBehaviourDataSequence;
      CBehaviourClientCallback *iBehaviourClientCallback; ///< Pointer to class instance containing callback functions.
      CBehaviourClient(const CBehaviourClient &) 
        : CSync(2,1),
          CThread(1),
          CMaCI(NULL, GIMI_PROTOCOL_MACI_BEHAVIOUR, 0,""),
          iBehaviourState(false),
          iBehaviourData(),
          iBehaviourInfo(),
          iBehaviourDataSequence(-1),
          iBehaviourClientCallback(NULL){}
      CBehaviourClient &operator=(const CBehaviourClient &) { return *this; }
    };
    
  }
}

#endif //_MACI_INTERFACE_BEHAVIOURCLIENT_HPP_
